"""
认证
"""

from functools import wraps

from starlette.requests import Request
from starlette.responses import Response
from typing_extensions import deprecated

from config import settings
from models.other import (
    JWTPayload,
    RequestRoute,
)
from models.po import (
    UserPO,
    UserTokenPO,
)
from my_typing import *
from utils.exception_utils import AuthenticationError
from utils.mock_utils import DATETIME


def _get_payload_from_request(request: Request) -> JWTPayload | None:
    """ 从请求中获取荷载 """

    from biz.user_token_biz import JWTHandler

    request_route: RequestRoute = request.scope["request_route"]
    auth_dependencies: SetStr = {"login_required", "admin_required"}
    """ 需要登录的依赖项 """

    if not set(request_route.dependencies) & auth_dependencies:
        return None

    authorization: StrOrNone = request.headers.get("Authorization")
    """
    验签的请求头

        - None: 未登录（无需抛出异常）
        - "": Token 为空（需要抛出异常）
        - 其他情况: 正常（需要验签）
    """

    if authorization is None:
        return None

    if not authorization:
        raise AuthenticationError("Token 为空")

    split_token: ListStr = authorization.split(" ")

    if len(split_token) != 2:
        raise AuthenticationError("Token 无效")

    prefix, token_key = split_token

    if prefix != settings.CONST.PROJECT_NAME:
        raise AuthenticationError("Token 前缀错误")

    try:
        payload: JWTPayload = JWTHandler.get_payload_by_token_key(token_key)

    except KeyError:
        raise AuthenticationError("Token 荷载错误")

    if payload.expire_time <= DATETIME.now():
        raise AuthenticationError("Token 已过期")

    return payload


def _get_user_by_payload(payload: JWTPayload | None) -> UserPO | None:
    """ 根据荷载获取用户 """

    from service import (
        UserService,
        UserTokenService,
    )

    if payload is None:
        return None

    user_token_po: UserTokenPO | None = UserTokenService.get_one_by_user_id(payload.user_id)

    if not user_token_po:
        raise AuthenticationError("用户不存在")

    return UserService.get_one_by_id(user_token_po.user_id)


def get_request_user(request: Request) -> UserPO | None:
    """ 获取请求的用户 """

    payload: JWTPayload | None = _get_payload_from_request(request)
    user_po: UserPO | None = _get_user_by_payload(payload)

    return user_po


@deprecated("🚨该方法已弃用，替换成依赖项 `components.depends.login_required`")
def login_required(async_func: Callable[..., Awaitable[Response]]) -> Callable[..., Awaitable[Response]]:
    """ 登录认证装饰器（异步） """

    @wraps(async_func)
    async def wrapper(*args, **kwargs) -> Response:
        from components.global_param import get_user_id

        if not get_user_id():
            raise AuthenticationError("请先登录")

        return await async_func(*args, **kwargs)

    return wrapper
